//! @file   lc_types.h
//! @brief  
//! @author Sayan Chaliha
//! @date   September, 2011
//!
//! 
#ifndef _LC_TYPES_H
#define _LC_TYPES_H

#include "libcyan_internal.h"

namespace cyan {
  typedef int8_t                  Int8;
  typedef uint8_t                 UInt8;
  typedef int16_t                 Int16;
  typedef uint16_t                UInt16;
  typedef int32_t                 Int32;
  typedef uint32_t                UInt32;
  typedef int64_t                 Int64;
  typedef uint64_t                UInt64;

  typedef Int8                    IntMin;
  typedef UInt8                   UIntMin;
  typedef Int32                   Int;
  typedef UInt32                  UInt;
  typedef Int64                   IntMax;
  typedef UInt64                  UIntMax;

#ifdef LC_ARCH_X86_64
  typedef Int64                   Register;
#elif defined (LC_ARCH_I386)
  typedef Int32                   Register;
#endif /* LC_ARCH_X86_64 */

  typedef char                    Char;
  typedef unsigned char           UChar;
  typedef wchar_t                 WChar;
#ifdef HAVE_WINT_T
  typedef wint_t                  WInt;
#else
  typedef WChar                   WInt;
#endif /* HAVE_WINT_T */
  typedef unsigned char           Byte;

  typedef time_t                  Time;
  typedef clock_t                 Clock;
  typedef Clock                   IntervalTime;

  typedef off_t                   Offset;
  typedef ptrdiff_t               PtrDiff;

  typedef size_t                  Size;
  typedef ssize_t                 SSize;

  typedef bool                    Bool;

  typedef double                  Double;
  typedef float                   Float;
  typedef long double             LDouble;

#if defined (HAVE_STRUCT_STAT_ST_DEV)
  typedef struct stat             FileStatus;
#elif defined (HAVE_STRUCT__STAT_ST_DEV)
  typedef struct _stat            FileStatus;
#endif /* HAVE_STRUCT_STAT_ST_DEV */

#if defined (HAVE_PTHREAD)
  typedef pthread_t               ThreadHandleType;
  typedef pthread_attr_t          ThreadAttributesType;
  typedef pthread_rwlock_t        MultiReaderLockType;
  typedef pthread_mutex_t         MutexType;
  typedef pthread_cond_t          ConditionVariableType;
  class GenericClass;
#elif defined (HAVE_WIN32_THREAD)
  typedef pthread_t               ThreadHandleType;
  typedef pthread_attr_t          ThreadAttributesType;
  typedef pthread_rwlock_t        MultiReaderLockType;
  typedef pthread_mutex_t         MutexType;
  typedef pthread_cond_t          ConditionVariableType;
  class __single_inheritance      GenericClass;
#endif /* HAVE_PTHREAD */
  class GenericClass {};

  template <typename T, T v>
  struct CYAN_API IntegralConstant {
    static const T                  value = v;
    typedef T                       ValueType;
    typedef IntegralConstant<T, v>  Type;
  };

  typedef IntegralConstant<Bool, true>    TrueType;
  typedef IntegralConstant<Bool, false>   FalseType;

  template <typename T, T v>
  const T IntegralConstant<T, v>::value;

  template <typename T>
  struct CYAN_API RemoveConst {
    typedef T   Type;
  };

  template <typename T>
  struct CYAN_API RemoveConst<const T> {
    typedef T   Type;
  };

  template <typename T>
  struct CYAN_API RemoveVolatile {
    typedef T   Type;
  };

  template <typename T>
  struct CYAN_API RemoveVolatile<volatile T> {
    typedef T   Type;
  };

  template <typename T>
  struct CYAN_API RemoveConstVolatile {
    typedef typename RemoveConst<typename RemoveVolatile<T>::Type>::Type Type;
  };

  namespace internal {
#ifdef HAVE__ATOMIC_WORD
    typedef _Atomic_word  _lc_AtomicWord;
#else
    typedef Int32         _lc_AtomicWord;
#endif /* HAVE__ATOMIC_WORD */

    template <typename> struct IsVoidHelper_             : public FalseType {};
    template <>         struct IsVoidHelper_<void>       : public TrueType  {};

    template <typename> struct IsIntegralHelper_         : public FalseType {};
    template <>         struct IsIntegralHelper_<Bool>   : public TrueType  {};
    template <>         struct IsIntegralHelper_<Int8>   : public TrueType  {};
    template <>         struct IsIntegralHelper_<UInt8>  : public TrueType  {};
    template <>         struct IsIntegralHelper_<Int16>  : public TrueType  {};
    template <>         struct IsIntegralHelper_<UInt16> : public TrueType  {};
    template <>         struct IsIntegralHelper_<Int32>  : public TrueType  {};
    template <>         struct IsIntegralHelper_<UInt32> : public TrueType  {};
    template <>         struct IsIntegralHelper_<Int64>  : public TrueType  {};
    template <>         struct IsIntegralHelper_<UInt64> : public TrueType  {};
    template <>         struct IsIntegralHelper_<Char>   : public TrueType  {};
    template <>         struct IsIntegralHelper_<WChar>  : public TrueType  {};
#ifdef LC_ARCH_X86_64
    template <>         struct IsIntegralHelper_<Size>   : public TrueType  {};
    template <>         struct IsIntegralHelper_<SSize>  : public TrueType  {};
#elif defined (LC_ARCH_I386)
    template <> struct IsIntegralHelper_<long int>          : public TrueType{};
    template <> struct IsIntegralHelper_<unsigned long int> : public TrueType{};
#endif /* LC_ARCH_X86_64 */

    template <typename, typename> struct AreSameHelper_   : public FalseType{};
    template <typename T>     struct AreSameHelper_<T, T> : public TrueType {};

    template <typename B, typename D>
    struct IsBaseOfHelper_ {
      typedef IntMin  True_  [2];
      typedef IntMax  False_ [1];

      static True_&   test(B*);
      static False_&  test(...);
      static D*       get();

      static const Bool value = sizeof (test(get())) == sizeof (True_);
    };

    template <typename T, typename U>
    struct AreComparableHelper_ {
      static Bool& constraint(T* a, U* b) {
        Bool result = *a == *b && *a != *b &&
            *a < *b && *a > *b && *a <= *b && *a >= *b;
        return result;
      }

      static const Bool value = sizeof (constraint(0, 0)) == sizeof (Bool);
    };

    template <typename T, typename U>
    struct AreCopyableHelper_ {
      static Bool constraint(T* a, U* b) {
        a = b;
        b = a;
        return true;
      }

      static const Bool value = sizeof (constraint(0, 0)) == sizeof (Bool);
    };

    template <typename T>
    struct IsCopyConstructableHelper_ {
      static Bool constraint(T* a) {
        T b(a);
        a = b;
        return true;
      }

      static const Bool value = sizeof (constraint(0)) == sizeof (Bool);
    };
  }

  template <typename T>
  struct CYAN_API IsVoid : public internal::IsVoidHelper_<typename
      RemoveConstVolatile<T>::Type>::Type {};

  template <typename T>
  struct CYAN_API IsIntegral : public internal::IsIntegralHelper_<typename
      RemoveConstVolatile<T>::Type>::Type {};
  
  template <typename B, typename D>
  struct CYAN_API IsBaseOf : public IntegralConstant<Bool,
      internal::IsBaseOfHelper_<B, D>::value> {};

  template <typename A, typename B>
  struct CYAN_API AreSame : public internal::AreSameHelper_<typename
      RemoveConstVolatile<A>::Type, typename RemoveConstVolatile<B>::Type> {};

  template <typename T, typename U = T>
  struct CYAN_API AreComparable : public IntegralConstant<Bool,
      internal::AreComparableHelper_<T, U>::value> {};

  template <typename A, typename B = A>
  struct CYAN_API AreCopyable : public IntegralConstant<Bool,
      internal::AreCopyableHelper_<A, B>::value> {};

  template <typename A>
  struct CYAN_API IsCopyConstructable : public IntegralConstant<Bool,
      internal::IsCopyConstructableHelper_<A>::value> {};

  template <typename T> struct CYAN_API IsPointer     : public FalseType {};
  template <typename T> struct CYAN_API IsPointer<T*> : public TrueType  {};

  template <Bool, typename T> struct CYAN_API EnableIf { typedef T Type; };
  template <typename T>       struct CYAN_API EnableIf<false, T> {};

  template <typename A, typename B>
  struct CYAN_API UnaryFunction {
    typedef A FirstType;
    typedef B ResultType;
  };

#ifndef HAVE_IMPLICIT_CAST
# define HAVE_IMPLICIT_CAST
  template <typename A, typename B>
  inline A CYAN_API implicit_cast(B object) {
    return static_cast<A>(object);
  }
#endif /* HAVE_IMPLICIT_CAST */

  template <typename A, typename B, typename C>
  struct CYAN_API BinaryFunction {
    typedef A FirstType;
    typedef B SecondType;
    typedef C ResultType;
  };

  template <typename A, typename B = A>
  struct CYAN_API less : public BinaryFunction<A, B, Bool> {
    typename EnableIf<AreComparable<A, B>::value, Bool>::Type
    operator ()(const A& a, const B& b) const {
      return a < b;
    }
  };

  template <typename A, typename B = A>
  struct CYAN_API more : public BinaryFunction<A, B, Bool> {
    typename EnableIf<AreComparable<A, B>::value, Bool>::Type
    operator ()(const A& a, const B& b) const {
      return a > b;
    }
  };
}

#endif /* _LC_TYPES_H */

